package core.reports;

import core.*;

import java.io.FileNotFoundException;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.itextpdf.text.DocumentException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * This class will create the Expired Items Report:
 * It will be responsible for getting the necessary data
 * through the visitor pattern, and then constructing the report
 * through the builder pattern.
 * 
 */
public class ExpiredItemsGuide implements IDirectorVisitor 
{
    ItemManager itemManager;
    ProductManager productManager;
    CoreFacade core;
    List<ExpiredItemsNode> expiredItems;
    
    /**
     * constructor
     */
    public ExpiredItemsGuide()
    {
        core = CoreFacade.getInstance();
        productManager = core.getPM();
        itemManager = core.getIM();
        //itemManager.getInstance();
        //productManager.getInstance();
        expiredItems = new ArrayList<ExpiredItemsNode>();
    }

    
    private class ExpiredItemComparable implements Comparator<Item>{
	 
	    @Override
	    public int compare(Item o1, Item o2) 
	    {
	    	//return o1.product.getDescription().compareTo(o2.product.getDescription());
	    	if (o1.getProduct().getDescription().compareTo(
	    			o2.getProduct().getDescription()) == 0)
	    	{
	    		return o1.getEntryDate().compareTo(o2.getEntryDate());
	    	}
	    	else
	    	{
	    		return o1.getProduct().getDescription().compareTo(
	    				o2.getProduct().getDescription());
	    	}
	    }
	}
        
        
    private List<Item> visitProductContainer(ProductContainer su, TraversalOrder order) 
    {
        Set<Item> sItems;
        List<Item> lItems;
        
        try
        {
            sItems = itemManager.getItemsFromContainer(su);
        }
        catch(Exception e){System.out.println("error!"); assert(false);
            return null;}
        
        //convert to list
        lItems = new ArrayList<Item>(sItems);
        //lItems = convertSetToItemList(sItems);
        List<Item> lItems2 = new ArrayList<Item>();
        
        for(Item i : lItems)
        {
            if(itemManager.isItemExpired(i))
            {
                lItems2.add(i);
            }
        }
        
        if(lItems2.isEmpty()) //short cut
            return null;
        
        //lItems2 = sort1(lItems2);
        //lItems2 = sort2(lItems2);
        Collections.sort(lItems2, new ExpiredItemComparable());
        
        return lItems2;
	}
    
	@Override
	/**
	 * When creating the Expired items report this method
	 * will get the necessary information from a product group
	 * @param pg the productGroup
	 * @return true if it was successful
	 */
	public boolean visitProductGroup(ProductGroup pg, TraversalOrder order) 
	{
        List<Item> lItems = visitProductContainer(pg, order);
        if (lItems == null) {return true;}
        
        //get the storage unit that the product group is in
        StorageUnit su = CoreFacade.getInstance().getParentStorageUnit(pg);
        
        /*while(!(su instanceof StorageUnit))
        {
            pg = (ProductGroup) su;
            su = pg.getParentContainer();
        }*/
        
        //StorageUnit sUnit = (StorageUnit)su;
        
        for(Item i : lItems)
        {
            ExpiredItemsNode ein = new ExpiredItemsNode(su, pg, 
            		i.getProduct().getDescription(), i);
            expiredItems.add(ein);
        }
        
        return true;
	}
        
	@Override
	/**
	 * When creating the Expired items report this method
	 * will get the necessary information from a storage unit
	 * @param su the storage unit
	 * @return true if it was successful
	 */
	public boolean visitStorageUnit(StorageUnit su, TraversalOrder order) 
	{
        List<Item> lItems = visitProductContainer(su, order);
        
        if (lItems == null) {return true;}
        
        for(Item i : lItems)
        {
            ExpiredItemsNode ein = new ExpiredItemsNode(su, null, 
            		i.getProduct().getDescription(), i);
            expiredItems.add(ein);
        }
        
        return true;
	}
        
    private List convertSetToItemList(Set<Item> s)
    {
        List<Item> listedItems = new ArrayList();
        
        Iterator<Item> itr = s.iterator();
        while(itr.hasNext())
        {
            listedItems.add(itr.next());
        }
        return listedItems;
    }
        
    private List<Item> sort1(List<Item> list)
    {
        Collections.sort(list, new Comparator<Item>() {
        @Override
        public int compare(Item o1, Item o2) {
                int compare = o1.getProduct().getDescription().compareTo(
                        o2.getProduct().getDescription());
                return compare;
            }
        });
        
        return list;
    }
        
    private List<Item> sort2(List<Item> list)
    {
        List<Item> sorted = new ArrayList();
        List<Item> sublist = new ArrayList();
        for(int i = 0; i < list.size(); i++)
        {
            if(sublist.isEmpty())
            {
                sublist.add(list.get(i));
            }
            if(i+1 < list.size()) //if i is the last one
            {
                for(Item itm : sublist)
                {
                    sorted.add(itm);
                }
                continue;
            }
            if(list.size() == 1)
            {
                continue;
            }
            //if this item has same description as items in sublist, add
            if(list.get(i).getProduct().getDescription()
                    .equals(list.get(i-1).getProduct().getDescription()))
            {
                sublist.add(list.get(i));
            }
            else //if not..
            {
                //..sort the sublist..
                Collections.sort(sublist, new Comparator<Item>() {
                @Override
                public int compare(Item o1, Item o2) {
                    Calendar cal = o1.getEntryDate();
                    if(cal.after(o2.getEntryDate()))
                    {
                        return 1;
                    }
                    else if(cal.before(o2.getEntryDate()))
                    {
                        return -1;
                    }
                    else
                    {
                        return 0;
                    }
                    }
                });
                //..and add sublist to sorted list.
                for(Item itm : sublist)
                {
                    sorted.add(itm);
                }
            }
            
            return sorted;
        }
        
        
        Collections.sort(list, new Comparator<Item>() {
        @Override
        public int compare(Item o1, Item o2) {
                int compare = o1.getProduct().getDescription().compareTo(
                        o2.getProduct().getDescription());
                return compare;
            }
        });
        
        return list;
    }

	
	
	@Override
	/**
	 * After getting the data from the visit methods, this will
	 * then instruct the appropriate builder how to create the 
	 * necessary report
	 * @return true if it was successful
	 */
	public String construct(String nameOfBuilder) 
	{
        String filePath = "";
        IBuilder builder;
        
        if(nameOfBuilder.equals(ReportConstants.HTML_BUILDER))
        {
            builder = new HTMLBuilder("reports/ExpiredItems-"
                    + new Date().getTime() + ".html");
            filePath = ((HTMLBuilder)builder).getFileName();
        }
        else
        {
            builder = new PDFBuilder("reports/ExpiredItems-"
                    + new Date().getTime() + ".pdf");
            filePath = ((PDFBuilder)builder).getFileName();
        }
        
        builder.addTitle("Expire Item");
        builder.addBlankLine();
        builder.addTable(6);
        builder.addColumnHeader("Description");
        builder.addColumnHeader("Storage Unit");
        builder.addColumnHeader("Product Group");
        builder.addColumnHeader("Entry Date");
        builder.addColumnHeader("Expire Date");
        builder.addColumnHeader("Item Barcode");
        
        for(ExpiredItemsNode ein : expiredItems)
        {
            builder.addCell(ein.getProductDescription());
            builder.addCell(ein.getStorageUnit().getName());

            //check if there is a product group
            ProductGroup pg = ein.getProductGroup();
            String pGroup = (pg == null) ? "" : pg.getName();
            builder.addCell(pGroup);
            
            SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");

            builder.addCell(sdf.format(ein.getItem().getEntryDate().getTime()));
            builder.addCell(sdf.format(ein.getItem().getExpirationDate().getTime()));
            builder.addCell(ein.getItem().getBarcodeString());
        }
        
        builder.closeCurrentTable();
        builder.finish();
        
        
        return filePath;
        
	}
}

